package com.asen.commons.core.jdbc.handler;

import com.asen.commons.core.base.domain.Core;
import com.asen.commons.core.utils.EntityUtils;
import com.asen.commons.utils.BaseAssert;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Types;

/**
 * Core
 *
 * @author Gary
 * @version 1.0
 * @date 2018-11-29
 */
public class CoreDoTypeHandler<T extends Core> extends BaseTypeHandler<T> {

    private Class<T> type;

    public CoreDoTypeHandler() {
    }

    public CoreDoTypeHandler(Class<T> type) {
        BaseAssert.notNull(type, "参数type不能为空");
        this.type = type;
    }

    @Override
    public int getSqlType() {
        return Types.BIGINT;
    }

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, T parameter)
            throws Exception {
        Long id = parameter.getId();
        BaseAssert.notNull(id, "参数 #" + i + "【" + parameter.getClass().getName() + "】 id 不能为空");
        ps.setLong(i, id);
    }

    @Override
    public T getNullableResult(ResultSet rs, String columnName)
            throws Exception {
        return convert(rs.getLong(columnName));
    }

    @Override
    public T getNullableResult(ResultSet rs, int columnIndex)
            throws Exception {
        return convert(rs.getLong(columnIndex));
    }

    @Override
    public T getNullableResult(CallableStatement cs, int columnIndex)
            throws Exception {
        return convert(cs.getLong(columnIndex));
    }

    private T convert(Long id) throws Exception {
        Class<T> modelClazz = null;
        if (this.type != null) {
            modelClazz = this.type;
        } else {
            modelClazz = getRefRawType();
        }

        T model = modelClazz.newInstance();
        model.setId(id);
        return model;
    }

    @Override
    public String toSqlValue(Object value) {
        if (value == null) {
            return null;
        }

        if (value instanceof Core) {
            Core coreDo = (Core) value;
            if (coreDo.getId() == null || coreDo.getId() == 0) {
                return null;
            }
            return String.valueOf(coreDo.getId());
        }

        if (value instanceof Long) {
            return String.valueOf(value);
        }

        if (value instanceof Core[]) {
            StringBuilder sb = new StringBuilder(0);
            sb.append("(");
            for (Core s : (Core[]) value) {
                if (sb.length() > 0) {
                    sb.append(", ");
                }
                sb.append(s.getId());
            }
            sb.append(")");
            return sb.toString();
        }

        if (value instanceof Long[]) {
            return getSqlValue((Long[]) value);
        }

        if (value instanceof long[]) {
            StringBuilder sb = new StringBuilder(0);
            sb.append("(");
            for (long s : (long[]) value) {
                if (sb.length() > 0) {
                    sb.append(", ");
                }
                sb.append(s);
            }
            sb.append(")");
            return sb.toString();
        }

        return String.valueOf(value);
    }

    @Override
    public T getValue(Object value) throws Exception {
        if (value == null) {
            return null;
        }

        if (this.type.equals(value.getClass())) {
            return (T) value;
        }

        if (Long.class.isAssignableFrom(value.getClass())) {
            T obj = this.type.newInstance();
            obj.setId((Long) value);
            return obj;
        }

        if(!EntityUtils.isSimpleType(value.getClass())) {
            T obj = this.type.newInstance();
            EntityUtils.copyProperties(value, obj);
            return obj;
        }

        return null;
    }
}
